#pragma once

#include <vector>
#include <functional>
#include "cs.pb.h"

template<typename T>
class CompareFunctor
{
public:
	bool operator()(const T& a, const T& b)
	{
		return a.first < b.first;
	}
};

template<typename V>
class KeyGetter
{
public:
	KeyGetter(const google::protobuf::Reflection* reflection,
		const google::protobuf::FieldDescriptor* field)
	{
		this->reflection = reflection;
		this->field = field;
	}

	void operator()(int& k, const V& r)
	{
		k = reflection->GetInt32(r, field);
	}

	void operator()(std::string& k, const V& r)
	{
		k = reflection->GetString(r, field);
	}

	const google::protobuf::FieldDescriptor* field;
	const google::protobuf::Reflection* reflection;
};

template<typename K, typename V>
class ConfigTable
{
public:
	typedef std::pair<K, V> Record;

	ConfigTable(std::string KeyName)
	{
		descriptor = V::GetDescriptor();
		reflection = V::GetReflection();
		field = descriptor->FindFieldByName(KeyName);
		func = CompareFunctor<Record>();
	}

	void AddRecord(const V& r)
	{
		K key;
		KeyGetter<V> gt(reflection, field);
		gt(key, r);
		data.push_back({ key, r });
	}

	const V* FindByID(K key)
	{
		Record r;
		r.first = key;
		auto result = std::equal_range(data.begin(), data.end(), r, func);
		if (result.first == result.second)
		{
			return nullptr;
		}
		else
		{
			return &((*result.first).second);
		}
	}

	void Sort()
	{
		std::sort(data.begin(), data.end(), func);
	}

	void PostLoad(std::function<int(std::vector<Record> &)> func)
	{
		func(data);
	}

private:
	const google::protobuf::FieldDescriptor* field;
	const google::protobuf::Descriptor* descriptor;
	const google::protobuf::Reflection* reflection;
	
	
	CompareFunctor<Record> func;
	std::vector<Record> data;
};